package com.example.studentpoint.utils

import android.os.Handler
import android.os.Looper
import android.util.Log
import com.example.studentpoint.global.AppConfig
import java.util.concurrent.LinkedBlockingDeque
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
import com.example.studentpoint.R
import com.example.studentpoint.domain.receive.Resp
import org.json.JSONObject
import java.lang.reflect.Method
import java.net.HttpURLConnection
import java.net.URL
import java.util.Date

/**
 * 网络请求工具类
 *
 * @author xxxz
 * {@code @date} 2025-10-25
 */
object HttpUtils {
    // 线程池
    val tp = ThreadPoolExecutor(
        10, 10, 10,
        TimeUnit.SECONDS, LinkedBlockingDeque()
    )
    // 基础 handler
    val handler = Handler(Looper.getMainLooper())
    // 获取基本 url
    val baseUrl = AppConfig.applicationContext.getString(R.string.api_url)

    /**
     * 得到url
     */
    private fun getUrl(method: String, uri: String) : HttpURLConnection{
        val con = URL("$baseUrl$uri").openConnection() as HttpURLConnection
        con.setRequestProperty("Content-Type", "application/json")
        con.requestMethod = method
        con.doInput = true
        con.doOutput = true
        Log.d("http url", "$baseUrl$uri")
        return con
    }

    /**
     * 接收网络请求结果
     */
    private fun receive(con: HttpURLConnection, func: (Resp) -> Unit) {
        if (con.responseCode != 200) {
            throw Exception(con.errorStream.bufferedReader().readText())
        } else {
            val res = jsonToObj(Resp::class.java, con.inputStream.bufferedReader().readText())
            if (res.code != 200) {
                throw Exception(res.msg)
            }

            func(res)
        }
    }

    /**
     * 对象转成 Json 字符串
     */
    private fun objToJson(data: Any): String {
        val obj = JSONObject()
        data::class.java.declaredFields.forEach {
            it.isAccessible = true
            obj.put(
                it.name,
                if (it[data] as? Date != null) DateUtils.format(it[data] as Date, true)
                else it[data]
            )
        }
        return obj.toString()
    }
    /**
     * json 字符串 转 对象
     */
    fun <T> jsonToObj(clazz: Class<T>, json: String) : T {
        val obj = JSONObject(json)
        val data = clazz.getDeclaredConstructor().newInstance()
        clazz.declaredFields.forEach {
            it.isAccessible = true
            var method: Method? = null
            try {
                method = it.type.getDeclaredMethod("valueOf", String::class.java)
            } catch (_: Exception) {}

            try {
                it.set(
                    data,
                    if (it.type == Date::class.java) DateUtils.parse("${obj[it.name]}")
                    else if (method != null) method.invoke(null, "${obj[it.name]}")
                    else obj[it.name]
                )
            } catch (_: Exception) {
            }
        }
        return data
    }

    /**
     * 选择发送基本类 get, delete 这些
     */
    fun send(method: String, url: String, func: (Resp) -> Unit) {
        tp.execute {
            if (method !in listOf("Get", "Delete")) {
                Log.e("http utils", "错误的请求方式")
                throw Exception("请输入正确的请求方式")
            }

            val con = getUrl(method, url)
            receive(con, func)
        }
    }

    /**
     * 选择发送基本类 post, put这些
     */
    fun send(method: String, url: String, data: Any, func: (Resp) -> Unit) {
        tp.execute {
            if (method !in listOf("Post", "Put")) {
                Log.e("http utils", "错误的请求方式")
                throw Exception("请输入正确的请求方式")
            }

            val con = getUrl(method, url)
            con.outputStream.apply {
                write(
                    if (data is String) data.toByteArray()
                    else objToJson(data).toByteArray()
                )
                flush()
            }
            receive(con, func)
        }
    }
}